using System;
using System.Threading;
using System.Collections.Generic;

namespace Jukebox
{
    public class Jukebox
    {
        static Jukebox mSelf;
        State mState;
        string mStateString;
        List<Command> mCommands = new List<Command>();
        Thread mThread;
        Semaphore mSemaphore = new Semaphore(0,25);
        Mutex mMutex = new Mutex();

        private Jukebox ()
        {
            mState = new Stopped();
            mStateString = mState.ToString();
        }
        
        public static Jukebox instance()
        {
            if( mSelf==null )
            {
                mSelf = new Jukebox();
            }
            return mSelf;
        }
        
        public void Start()
        {
            mCommands.Add(new StartCommand());
            if( mThread == null )
            {
                mThread = new Thread(Run);
                mThread.Start();
            }
        }
        
        public void Stop()
        {
            mCommands.Add(new StopCommand());
            mThread.Join();
            mThread = null;
        }

        protected void Run()
        {
            // Wait for signal 
            while( true )
            {
                // Extract the next command if there is one
                Command cmd = null;
                mMutex.WaitOne();
                mStateString = mState.ToString();
                if( mCommands.Count > 0 )
                {
                    cmd = mCommands[0];
                    mCommands.RemoveAt(0);
                }
                mMutex.ReleaseMutex();
                if( cmd != null )
                {
                    // Execute command
                    cmd.Execute(mState);
                }
                // Progress state
                mState = mState.Continue();
                if ((mState as Stopped) != null) return;
            }
        }
        
        public override string ToString ()
        {
            mMutex.WaitOne();
            string str = mStateString;
            mMutex.ReleaseMutex();
            return str;
        }
        
    }
}

